﻿Imports Microsoft.Office.Interop.Word
Imports System.Text.RegularExpressions

Public Class RankFix
    Private Const PERCENT = 0
    Private Const MESSAGE = 1
    Private Const EXCEPTION = 2

    Private filename As String
    Private canceled As Boolean

    Public Event Update(id As String, type As Integer, content As String)

    Public Sub New(filename As String)
        Me.filename = filename
    End Sub

    Public Sub Cancel()
        Me.canceled = True
    End Sub

    Public Sub Fix(id As String)
        Dim app = New Application()
        Dim doc = app.Documents.Open(Me.filename)

        Me.canceled = False

        Try
            Dim count = doc.Paragraphs.Count
            Dim currentPercent = -1

            Dim i = 0
            Dim curLevel = "0"

            For Each p As Paragraph In doc.Paragraphs
                i = i + 1
                If Me.canceled Then
                    Throw New Exception("Hủy bỏ bởi người sử dụng")
                End If

                Dim percent As Integer = i * 100 / count
                If (percent - 1) Mod 5 = 0 And percent > currentPercent Then
                    currentPercent = percent
                    RaiseEvent Update(id, RankFix.PERCENT, String.Format("Hoàn thành {0}%", percent))
                End If

                Dim outlineLevel = WdOutlineLevel.wdOutlineLevelBodyText

                Dim regex As New Regex("^\s*(?<level>\d+(\.\d+)*)\s*(?<rest>.+)$")
                Dim match = regex.Match(p.Range.Text)
                If match.Success Then
                    Dim level = match.Groups("level").Value
                    If level = "3.2.1" Then
                        Dim r = 1
                    End If
                    Dim rest = match.Groups("rest").Value
                    Dim dotCount = level.Split(".").Length - 1

                    If level = "1" AndAlso rest.Contains("概要") Then
                        outlineLevel = WdOutlineLevel.wdOutlineLevel2
                        curLevel = "1"
                    ElseIf dotCount = 0 AndAlso rest.Length < 5 Then
                        outlineLevel = WdOutlineLevel.wdOutlineLevelBodyText
                    ElseIf level = Me.NextLevel(curLevel, dotCount) AndAlso Not rest.StartsWith(")") Then
                        curLevel = level

                        Select Case dotCount
                            Case 0
                                outlineLevel = WdOutlineLevel.wdOutlineLevel2
                            Case 1
                                outlineLevel = WdOutlineLevel.wdOutlineLevel3
                            Case 2
                                outlineLevel = WdOutlineLevel.wdOutlineLevel4
                            Case 3
                                outlineLevel = WdOutlineLevel.wdOutlineLevel5
                            Case 4
                                outlineLevel = WdOutlineLevel.wdOutlineLevel6
                            Case Else
                                outlineLevel = WdOutlineLevel.wdOutlineLevelBodyText
                        End Select
                    End If
                End If
                If outlineLevel <> p.OutlineLevel Then
                    p.OutlineLevel = outlineLevel
                    RaiseEvent Update(id, RankFix.MESSAGE, String.Format("{0} --> {1}", p.Range.Text, Me.GetLevel(outlineLevel)))
                End If
            Next
            doc.SaveAs("c:\temp\new1.doc")
        Catch ex As Exception
            RaiseEvent Update(id, RankFix.EXCEPTION, ex.Message)
        Finally
            doc.Close()
            app.Quit(False)
        End Try
    End Sub

    Private Function GetLevel(level As WdOutlineLevel) As String
        Select Case level
            Case WdOutlineLevel.wdOutlineLevelBodyText
                Return "Body Text"
            Case WdOutlineLevel.wdOutlineLevel1
                Return "Level 1"
            Case WdOutlineLevel.wdOutlineLevel2
                Return "Level 2"
            Case WdOutlineLevel.wdOutlineLevel3
                Return "Level 3"
            Case Else
                Return "NG"
        End Select
    End Function

    Private Function NextLevel(curLevel As String, dotCount As Integer) As String
        Dim levels = curLevel.Split(".")
        If dotCount >= levels.Length + 1 Then
            Return String.Empty
        End If

        If dotCount = levels.Length Then
            Return curLevel + ".1"
        Else
            Dim list = New List(Of String)
            For i = 0 To dotCount - 1
                list.Add(levels(i))
            Next
            list.Add(((Integer.Parse(levels(dotCount)) + 1).ToString()))

            Return String.Join(".", list.ToArray())
        End If
    End Function
End Class

Public Class MapItem
    Public Level As Integer
    Public Text As String

    Public Sub New(p As Paragraph)
        Me.Level = p.OutlineLevel
        Me.Text = p.Range.Text
    End Sub
End Class

Public Class Level
    Public Value As Integer
    Public Text As String

    Public Sub New(value As Integer, text As String)
        Me.Value = value
        Me.Text = text
    End Sub
End Class